package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.SingletonBeanRegistry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 默认的单例注册表实现类
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    /**
     * 一级缓存：存放完整的bean对象 包括代理bean，普通bean，工厂bean
     */
    private Map<String, Object> singletonObjects = new HashMap<>();

    /**
     * 二级缓存：用来存放半成品的bean，比如没有设置属性的实例化bean 既有代理bean也有普通bean 但是都是半成品的
     * 而且二级缓存没有暴露对外的方法 只能通过三级缓存来调度到二级缓存 三级缓存像是一个中间存放处 而二级缓存像是一个目的地
     */
    private Map<String, Object> earlySingletonObjects = new HashMap<>();

    /**
     * 三级缓存：用来存放半成品的bean的实例对象 存放进去的bean如果需要被代理 则存放代理bean
     * 三级缓存里存的bean 被取一次就跑到二级缓存里去了
     */
    private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>();


    //有销毁方法的bean的集合
    private final Map<String, DisposableBean> disposableBeans = new HashMap<>();

    /**
     * 获取bean的方法
     * @param beanName
     * @return
     */
    @Override
    public Object getSingleton(String beanName) {
        //先从一级缓存中取bean对象
        Object singletonObject = singletonObjects.get(beanName);
        //一级缓存没有再从二级缓存取
        if(singletonObject == null){
            singletonObject = earlySingletonObjects.get(beanName);
            //二级缓存没有再查三级缓存
            if(singletonObject ==null){
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
                //三级缓存查到
                if(singletonFactory != null){
                    singletonObject = singletonFactory.getObject();

                    //将当前的代理bean从三级缓存移到二级缓存
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    @Override
    public void addSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);//1
        //增加到一级缓存 之后 就要把二级和三级缓存给清理
        earlySingletonObjects.remove(beanName);//2
        singletonFactories.remove(beanName);//3
    }

    /**
     * 增加代理bean的半成品实例
     * @param beanName
     * @param singletonFactory
     */
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        singletonFactories.put(beanName, singletonFactory);
    }

    /**
     * 注册到有销毁方法的bean里
     * @param beanName
     * @param bean
     */
    public void registerDisposableBean(String beanName, DisposableBean bean){
        disposableBeans.put(beanName, bean);
    }

    /**
     * 销毁所有带有销毁方法的bean集合
     * 这个集合里的DisposableBean对象 其实都是DisposableBeanAdapter对象 传递的时候就封装好了
     */
    public void destroySingletons() {
        ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
        for (String beanName : beanNames) {
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                //其实调用的都是DisposableBeanAdapter的destroy方法
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }
}
